//
//  NSString+Addition.m
//  Project
//
//  Created by  CarlsonLee on 2018/12/7.
//  Copyright © 2018年 YANJING. All rights reserved.
//

#import "NSString+Addition.h"
#import "NSCharacterSet+Addition.h"

static BOOL g_allowedCharacters = NO;
static BOOL g_stringByRemovingPercentEncoding = NO;
@implementation NSString (Addition)

#pragma mark - 编解码

- (NSString *)gel_stringByURLEncode {
    return [self gel_stringByURLEncode:NSUTF8StringEncoding];
}

- (NSString *)gel_stringByURLDecode {
    return [self gel_stringByURLDecode:NSUTF8StringEncoding];
}

- (NSString *)gel_stringByURLEncode:(NSStringEncoding)encoding {
    
    static NSString * const  allowedCharacters = @"!*'();:@&-=+$,./?%#[]";
    g_allowedCharacters = [NSString instancesRespondToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)];
    if (g_allowedCharacters) {
        static NSCharacterSet * characterSet = nil;
        if (characterSet == nil) {
            characterSet = [NSCharacterSet characterSetWithCharactersInString:allowedCharacters];
        }
        return  [self stringByAddingPercentEncodingWithAllowedCharacters:characterSet];
    } else {
        CFStringRef escaped = NULL;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        escaped = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                          (CFStringRef)self,
                                                          NULL,
                                                          (CFStringRef)allowedCharacters,
                                                          (CFStringEncoding)encoding);
#pragma clang diagnostic pop
        
#if defined(__has_feature) && __has_feature(objc_arc)
        return CFBridgingRelease(escaped);
#else
        return [(NSString *)escaped autorelease];
#endif
    }
}

- (NSString *)gel_stringByURLDecode:(NSStringEncoding)encoding {
    
    g_stringByRemovingPercentEncoding = [NSString instancesRespondToSelector:@selector(stringByRemovingPercentEncoding)];
    NSMutableString *resultString = [NSMutableString stringWithString:self];
    [resultString replaceOccurrencesOfString:@"+"
                                  withString:@" "
                                     options:NSLiteralSearch
                                       range:NSMakeRange(0, [resultString length])];
    
    
    if (g_stringByRemovingPercentEncoding) {
        return resultString.stringByRemovingPercentEncoding;
    }else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        return [resultString stringByReplacingPercentEscapesUsingEncoding:encoding];
#pragma clang diagnostic pop
    }
}

#pragma mark - md5

- (NSString* )gel_md5String
{
    return [[self dataUsingEncoding:NSUTF8StringEncoding] gel_md5String];
}

#pragma mark - 绘制
- (CGSize )gel_sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode
{
    CGSize result;
    if (!font) font = [UIFont systemFontOfSize:12];
    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        NSMutableDictionary *attr = @{}.mutableCopy;
        attr[NSFontAttributeName] = font;
        if (lineBreakMode != NSLineBreakByWordWrapping) {
            NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
            paragraphStyle.lineBreakMode = lineBreakMode;
            attr[NSParagraphStyleAttributeName] = paragraphStyle;
        }
        CGRect rect = [self boundingRectWithSize:size
                                         options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                      attributes:attr context:nil];
        result = rect.size;
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
#pragma clang diagnostic pop
    }
    return CGSizeCeil(result);
}

- (CGFloat)gel_widthForFont:(UIFont *)font {
    CGSize size = [self gel_sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
    return size.width;
}

- (CGFloat)gel_heightForFont:(UIFont *)font width:(CGFloat)width {
    CGSize size = [self gel_sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping];
    return size.height;
}

- (CGFloat)heightForString:(NSString *)str font:(UIFont *)font width:(CGFloat)width {
    CGFloat height;
    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        CGRect rect = [str boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
                                        options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                     attributes:@{ NSFontAttributeName: font } context:nil];
        height = rect.size.height;
        height += 1;
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [str sizeWithFont:font constrainedToSize:CGSizeMake(width, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
#pragma clang diagnostic pop
        height = size.height;
    }
    return height;
}

- (CGFloat)gel_heightForFont:(UIFont *)font width:(CGFloat)width line:(NSInteger)line {
    NSMutableString *test = NSMutableString.new;
    for (int i=0; i<line; i++) {
        [test appendString:@"字"];
    }
    CGFloat maxHeight = [self heightForString:test font:font width:1];
    CGFloat height = [self heightForString:self font:font width:width];
    return height > maxHeight ? maxHeight : height;
}

#pragma mark - 正则
- (BOOL)gel_matchesRegex:(NSString *)regex {
    NSError *error = nil;
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionAnchorsMatchLines error:&error];
    if (error) {
        NSLog(@"NSString+Addition create regex error: %@", error);
        return NO;
    }
    return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0);
}

- (void)gel_enumerateRegexMatches:(NSString *)regex usingBlock:(void (^)(NSString *match, NSInteger index, NSRange matchRange, BOOL *stop))block {
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionAnchorsMatchLines error:nil];
    NSArray *matches = [pattern matchesInString:self options:0 range:NSMakeRange(0, self.length)];
    
    if (matches.count > 0) {
        [matches enumerateObjectsUsingBlock: ^(NSTextCheckingResult *result, NSUInteger idx, BOOL *stop) {
            block([self substringWithRange:result.range], idx, result.range, stop);
        }];
    }
}

- (void)gel_enumerateRegexMatches:(NSString *)regex caseInsensitive:(BOOL)caseIns usingBlock:(void (^)(NSString *match, NSInteger index, NSRange matchRange, BOOL *stop))block {
    NSRegularExpressionOptions op = NSRegularExpressionAnchorsMatchLines;
    if (caseIns) {
        op |= NSRegularExpressionCaseInsensitive;
    }
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:op error:nil];
    NSArray *matches = [pattern matchesInString:self options:0 range:NSMakeRange(0, self.length)];
    
    if (matches.count > 0) {
        [matches enumerateObjectsUsingBlock: ^(NSTextCheckingResult *result, NSUInteger idx, BOOL *stop) {
            block([self substringWithRange:result.range], idx, result.range, stop);
        }];
    }
}

- (NSString *)gel_stringByReplacingRegex:(NSString *)regex withString:(NSString *)replacement {
    NSError *error = nil;
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionAnchorsMatchLines error:&error];
    if (error) {
        NSLog(@"NSString+LFAdd create regex error: %@", error);
        return nil;
    }
    return [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement];
}

#pragma mark - General
+ (NSString *)gel_stringWithUUID {
    CFUUIDRef uuid = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    CFRelease(uuid);
    return (__bridge_transfer NSString *)string;
}

- (NSString *)gel_stringByTrim {
    NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    return [self stringByTrimmingCharactersInSet:set];
}

- (NSData *)gel_dataValue {
    return [self dataUsingEncoding:NSUTF8StringEncoding];
}

- (id)gel_jsonValueDecoded {
    return [[self gel_dataValue] gel_jsonValueDecoded];
}

- (BOOL)gel_containsEmoji {
    return [self gel_containsCharacterSet:[NSCharacterSet gel_emojiCharacterSet]];
}

+ (BOOL)gel_stringIsNull:(NSString *)string {
    BOOL result = NO;
    if (NULL == string ||
        [string isEqual:nil] ||
        [string isEqual:Nil]){
        result = YES;
        
    }else if ([string isEqual:[NSNull null]]){
        result = YES;
    }else if (0 == [string length] ||
              0 == [[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length]){
        result = YES;
    }else if([string isEqualToString:@"(null)"] ||
             [string isEqualToString:@"null"] ||
             [string isEqualToString:@"<null>"]){
        result = YES;
    }
    return result;
}

- (BOOL)gel_containsString:(NSString *)string {
    if (string == nil) return NO;
    return [self rangeOfString:string].location != NSNotFound;
}

- (BOOL)gel_containsCharacterSet:(NSCharacterSet *)set {
    if (set == nil) return NO;
    return [self rangeOfCharacterFromSet:set].location != NSNotFound;
}

- (NSString *)gel_stringNamed:(NSString *)name {
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
    NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    return str;
}

- (NSString *)gel_segmentString {
    NSMutableString *str = [NSMutableString stringWithString:self];
    NSInteger count = floorf((CGFloat)self.length / 3);
    if (self.length % 3 == 0) {
        count = floorf((CGFloat)self.length / 3) - 1;
    }
    for (int i = 0; i < count; i ++) {
        [str insertString:@"," atIndex: (str.length - (3*(i + 1) + i))];
    }
    return str;
}

- (BOOL)gel_equalToStrObj:(id )obj
{
    if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSMutableString class]] || [obj respondsToSelector:@selector(gel_equalToObj:)]) {
        return [(NSString *)obj isEqualToString:self];
    } else {
        NSLog(@"gel_equalToObj对象不是NSString");
        return NO;
    }
}

+ (NSString* )gel_safeStr:(NSString* )string
{
    if ([string isKindOfClass:[NSNumber class]]) {
        NSNumber *numS = (NSNumber *)string;
        return [numS stringValue];
        
    }else if ([self gel_stringIsNull:string]) {
        return @"";
    }
    return [NSString stringWithFormat:@"%@",string];
}
@end
